//-----------------------------------------------------------------------------
//  File          : sysutil.c
//  Module        :
//  Description   : Common Utilities Functions
//  Author        : Lewis
//  Notes         :
//
// ============================================================================
// | Naming conventions                                                       |
// | ~~~~~~~~~~~~~~~~~~                                                       |
// |         Struct/Array : Leading s                                         |
// |             Constant : Leading K                                         |
// |      Global Variable : Leading g  (variable use outside one C file)      |
// |                                                                          |
// |   BYTE( 8 Bits) size : Leading b                                         |
// |   CHAR( 8 Bits) size : Leading c                                         |
// |   WORD(16 Bits) size : Leading w                                         |
// |  DWORD(32 Bits) size : Leading d                                         |
// |    int(32 Bits) size : Leading i                                         |
// | DDWORD(64 Bits) size : Leading dd                                        |
// |              Pointer : Leading p                                         |
// |                                                                          |
// |    Function argument : Leading a                                         |
// |       Local Variable : All lower case                                    |
// |                                                                          |
// | Examples:                                                                |
// |                Array : Leading s, (sb = arrary of byte, etc)             |
// |              Pointer : Leading p, (pb = pointer of byte, etc)            |
// ============================================================================
//
//  Date          Who         Action
//  ------------  ----------- -------------------------------------------------
//  01 Feb  2010  Lewis       Initial Version.
//-----------------------------------------------------------------------------
#include <stdio.h>
#include <string.h>
#include "midware.h"
#include "system.h"
#include "util.h"
#include "coremain.h"
#include "sysutil.h"


//----------------------------------------------------------------------------
// Defines
//----------------------------------------------------------------------------
#define FLASH_START_ADDRESS         0x00100000
#define SRAM_END_ADDRESS            0x002FFFFF

// Disp Commands
#define SU_DELEOL              0x05
#define SU_PUSHCURSOR          0x0D
#define SU_POPCURSOR           0x0E
#define SU_SELSMFONT           0x10
#define SU_SELBIGFONT          0x11
#define SU_SELSPFONT           0x12
#define SU_ESC                 0x1B


#define LINE_CTRL(x)           (x&0x0F)
#define LINE_FONT(x)           (x&0xF000)
#define FONT_IDX(x)            (x>>12)

//-----------------------------------------------------------------------------
//    Constant
//-----------------------------------------------------------------------------
#ifdef T800
const BYTE KLineSize[] = { 20, 20, 26, 20,
                           20, 20, 26, 20};
#else
const BYTE KLineSize[] = { 16, 16, 21, 16,
                           16, 16, 21, 16};
#endif
#if (R700)
const BYTE KFontCode[] = { K_SelSmFont,   K_SelBigFont, K_SelSpFont,  K_SelSpChnFont,
                           K_SelUser8x16, K_SelUser8x8, K_SelUser6x8, K_SelUser8x16T};
#else
const BYTE KFontCode[] = { K_SelSmFont,   K_SelBigFont, K_SelSpFont,  K_SelBigFont,
                           K_SelUser8x16, K_SelUser8x8, K_SelUser6x8, K_SelUser8x16T};
#endif

//-----------------------------------------------------------------------------
//      Globals
//-----------------------------------------------------------------------------

//*****************************************************************************
//  Function        : Delay10ms
//  Description     : Delay a number of 10ms .
//  Input           : cnt; // count of 10ms to Delay
//  Return          : N/A
//  Note            : os_sleep() delay 5ms.
//  Globals Changed : N/A
//*****************************************************************************
void Delay10ms(DWORD aCnt)
{
  aCnt *= 2;
  while (aCnt--) os_sleep();
}
//*****************************************************************************
//  Function        : AcceptBeep
//  Description     : Generate a beep sound for accept.
//  Input           : N/A
//  Return          : N/A
//  Note            : 3 X 100ms
//                    Assume buzzer is ready.
//  Globals Changed : N/A
//*****************************************************************************
void AcceptBeep(void)
{
  os_beep_sound(10, 10, 3);
}
//*****************************************************************************
//  Function        : LongBeep
//  Description     : Generate long beep sound.
//  Input           : N/A
//  Return          : N/A
//  Note            : Assume buzzer is ready.
//  Globals Changed : N/A
//*****************************************************************************
void LongBeep(void)
{
  os_beep_sound(30, 9, 1);
}
//*****************************************************************************
//  Function        : ClearLine
//  Description     : Clear the specify line.
//  Input           : aLineNo;  // line number of the line to be clear
//  Return          : TRUE/FALSE;
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
DWORD ClearLine(DWORD aLineNo, DWORD aReverse)
{
  BYTE tmpbuf[64], *ptr;

  ptr = tmpbuf;
  
  if (aReverse)  *ptr++ = SU_REV_ON;
  *ptr++ = SU_ESC;
#if T800 
  *ptr++ = LINE_NO(aLineNo);
  *ptr++ = (LINE_POS(aLineNo)==0x00)?0x01:LINE_POS(aLineNo);
#else  
  *ptr++ =(BYTE)(LINE_NO(aLineNo)|LINE_POS(aLineNo));
#endif  
  *ptr++ = SU_DELEOL;
  if (aReverse)  *ptr++ = SU_REV_OFF;
  os_disp_putn(tmpbuf, ptr-tmpbuf);
  return TRUE;
}
//*****************************************************************************
//  Function        : ClrBelow
//  Description     : Clear the lines below selection.
//  Input           : aLineNo;
//  Return          : TRUE/FALSE;
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
DWORD ClrBelow(DWORD aLineNo)
{
  DWORD line_tmp = SU_MAX_LINE;

  os_disp_putc(SU_PUSHCURSOR);
  os_disp_putc(SU_SELSMFONT);
  do {
    ClearLine(line_tmp, FALSE);
    if (line_tmp <= aLineNo)
      break;
    line_tmp -= (SU_LINE3-SU_LINE2);
  } while (1);
  os_disp_putc(SU_POPCURSOR);
  return TRUE;
}
//*****************************************************************************
//  Function        : DispGotoXY
//  Description     : Set Cursor Position.
//  Input           : aOffset;      // LINE + LINE OFFSET
//                    aFont;        // FONT IDX
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
DWORD DispGotoXY(DWORD aOffset, DWORD aFont)
{
  BYTE tmp[4];

  tmp[0] = KFontCode[FONT_IDX(aFont)];
  tmp[1] = SU_ESC;
#if T800
  tmp[2] = LINE_NO(aOffset) == 0 ? 1: LINE_NO(aOffset);
  tmp[3] = LINE_POS(aOffset) == 0 ? 1 : LINE_POS(aOffset);
  os_disp_putn(tmp, 4);
#else
  tmp[2] = (LINE_NO(aOffset)|LINE_POS(aOffset));
  os_disp_putn(tmp, 3);
#endif
  return TRUE;
}
//*****************************************************************************
//  Function        : DispLine
//  Description     : Display Line Data
//  Input           : aMsg;         // pointer to message string
//                    aOffset;      // line no + line offset
//                    aCtrl;        // Control + font
//  Return          : TRUE/FALSE;
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
DWORD DispLine(const void *aMsg, DWORD aOffset, DWORD aCtrl)
{
  DWORD disp_len, line_size;
  BYTE  disp_buf[SU_MAX_LINESIZE+3], *ptr;

  line_size = KLineSize[FONT_IDX(aCtrl)<MAX_SU_FONT?FONT_IDX(aCtrl):MAX_SU_FONT-1];
  memset(disp_buf, ' ', sizeof(disp_buf));
  disp_len = strlen(aMsg);
  disp_len = disp_len > line_size ? line_size : disp_len;
  ptr = disp_buf;
  if (aCtrl&SU_REVERSE) {
    *ptr++ = SU_REV_ON;
  }
  switch (LINE_CTRL(aCtrl)) {
    case SU_CENTER:
      memcpy((ptr+(line_size-disp_len)/2), aMsg, disp_len);
      disp_len = KLineSize[FONT_IDX(aCtrl)];
      ptr += disp_len;
      break;
    case SU_RIGHT:
      aOffset |= (line_size-disp_len);
      memcpy(ptr, aMsg, disp_len);
      ptr += disp_len;
      break;
    case SU_LEFT:
    default:
      memcpy(ptr, aMsg, disp_len);
      ptr += disp_len;
  }
  if (aCtrl&SU_REVERSE) {
    *ptr++ = SU_REV_OFF;
  }
  if (aCtrl&SU_CLRDISP) {
    DispCtrl(SU_CLRHOME);
  }

  if (aCtrl&SU_CLREOL) {
    ClearLine(aOffset, (aCtrl&SU_REVERSE));
  }
//  else if ((LINE_CTRL(aCtrl)==SU_CENTER) && (LINE_FONT(aCtrl)==SU_SPFONT)) {
//    ClearLine(aOffset, (aCtrl&SU_REVERSE));
//  }

  DispGotoXY(aOffset, aCtrl);
  os_disp_putn(disp_buf, (ptr-disp_buf));
  return TRUE;
}
//*****************************************************************************
//  Function        : ClrAllFiles
//  Description     : Remove All old files.
//  Input           : N/A
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
void ClrAllFiles(void)
{
  T_FILE *pfile_hdr, file_hdr;

  // Clear Up all old files
  pfile_hdr = os_file_search_data(K_SearchReset, &file_hdr);
  while (pfile_hdr != NULL) {
    os_file_delete(file_hdr.s_name);
    pfile_hdr = os_file_search_data(K_SearchReset, &file_hdr);
  }
}
//*****************************************************************************
//  Function        : MemFatalErr
//  Description     : Check for valid memory allocated pointer.
//                    Err: Prompt Error Message & Reset.
//  Input           : aMemPtr;          // pointer to allocated memory
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
void MemFatalErr(void *aMemPtr)
{
  if (aMemPtr == NULL) {
    DispLine("Memory Error !", SU_LINE3, SU_CLRDISP|SU_REVERSE|SU_CENTER|SU_BIGFONT);
    LongBeep();
    while (os_kbd_getkey() == 0) os_sleep();
    os_reset();
  }
}
//*****************************************************************************
//  Function        : CommitFileIO
//  Description     : Just want to make sure the previous file IO had been done.
//  Input           : N/A
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
void CommitFileIO(void)
{
  // make sure the above process is completed
  int fd = -1;
  while (fd == -1) {
    if (os_file_exist(KSoftName)) {
      fd = os_file_delete(KSoftName);
    }
    fd = os_file_create(KSoftName, K_FILE_ACTIVE|K_FILE_USR_WRITE|K_FILE_USR_READ);
    if (fd < 0)
      continue;
    os_file_write(fd, KSoftName, strlen(KSoftName));
    while (!os_file_flushed(fd));
    os_file_close(fd);
    break;
  };
}
//*****************************************************************************
//  Function        : CheckPointerAddr
//  Description     : Check whether pointer is syster pointer (stack or malloc)
//                    or not
//  Input           : aPtr
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
void CheckPointerAddr(void *aPtr)
{
#ifndef WIN32
  DWORD address;

  address = (DWORD)aPtr;
  if ((address < FLASH_START_ADDRESS) || (address > SRAM_END_ADDRESS))
    return;

  printf("\x0E\x1B\xE0\x1CNot A Valid Pointer!!\x1D\x0F");
  LongBeep();
  while (os_kbd_getkey() == 0) os_sleep();
#endif
}
//*****************************************************************************
//  Function        : FreeRunSec
//  Description     : Return Number of seconds since 1 Jan 1970.
//  Input           : N/A
//  Return          : N/A
//  Note            : N/A
//  Globals Changed : N/A
//*****************************************************************************
DWORD FreeRunSec(void)
{
  BYTE rtc[15];

  os_rtc_get(rtc);
  return RTC2UNIX(rtc);
}

//*****************************************************************************
//  Function        : DelaySec
//  Description     : Delay for certain time.
//  Input           : aSec;       // Number of seconds to be delay
//  Return          : N/A
//  Note            : os_sleep() is 5ms.
//  Globals Changed : N/A
//*****************************************************************************
void DelaySec(DWORD aSec)
{
  aSec *= 200;
  while (aSec--) os_sleep();
}
